package com.itheima.reggie.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.dto.PageDto;
import com.itheima.reggie.mapper.CategoryMapper;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishService;
import com.itheima.reggie.service.SetmealService;
import com.itheima.reggie.web.R;
import com.itheima.reggie.web.exception.BusinessException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.List;

/**
 * 分类业务层实现类
 *
 * @Author Vsunks.v
 * @Blog blog.sunxiaowei.net/996.mba
 * @Description: 分类业务层实现类
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Autowired
    CategoryMapper categoryMapper;


    /**
     * 当跨模块调用方法时，一般是注入对应模块的service对象，而非mapper对象
     * 考虑到代码复用和事务管理等因素。
     */
    @Autowired
    DishService dishService;

    @Autowired
    SetmealService setmealService;

    /**
     * 重写save方法，方法内部校验分类名称是否重复；重复后手动抛出业务异常
     *
     * @param entity 要保存的分类实体独享
     * @return 是否保存成功
     */
    @Override
    public boolean save(Category entity) {

        // TODO 参数校验

        // 根据分类名查询
       /*  String name = entity.getName();
        LambdaQueryWrapper<Category> qw = Wrappers.lambdaQuery(Category.class)
                .eq(StringUtils.isNotBlank(name), Category::getName, name);

        Category categoryInDb = this.getOne(qw);

        // 如果查到的对象不为null，说明存在，则抛出异常
        if (!ObjectUtils.isEmpty(categoryInDb)) {
            throw new BusinessException("分类名[" + name + "]重复，请修改后再试！");
        } */

        checkNameDuplacate(entity);

        // 否则，保存新增
        return super.save(entity);
    }


    /**
     * 分页查询
     *
     * @param pageDto 分页参数
     * @return 查询到的数据
     */
    @Override
    public R<Page<Category>> page(PageDto pageDto) {
        // 分页参数合理化设置
        Integer pageNum = pageDto.getPage();
        Integer pageSize = pageDto.getPageSize();

        if (pageNum == null) {
            pageNum = 1;
        }
        if (pageSize == null) {
            pageSize = 10;
        }


        // 封装分页条件对象
        Page<Category> page = new Page<>(pageNum, pageSize);

        // 封装查询条件对象(排序规则)
        LambdaQueryWrapper<Category> qw = Wrappers.lambdaQuery(Category.class)
                .orderByAsc(Category::getSort)
                .orderByDesc(Category::getUpdateTime);

        // 分页查询
        this.page(page, qw);

        // 组织数据并返回
        // 脱敏。 不要手动脱敏，使用jackson的注解@JsonIgnore 可以让指定的字段不参与Json序列化
        return R.success(page);
    }


    /**
     * 根据id删除分类，删除时检查是否正在使用
     *
     * @param id 要删除的分类的id
     * @return 是否删除成功
     */
    @Override
    public R removeByIdCheckUsing(Long id) {
        // 参数校验

        // 根据分类id查询菜品/套餐
        LambdaQueryWrapper<Dish> dlqw = Wrappers.lambdaQuery(Dish.class)
                .eq(Dish::getCategoryId, id);


        // 如果查询到的菜品，表示在使用，要抛出业务异常
        int dishCount = dishService.count(dlqw);
        if (dishCount > 0) {
            throw new BusinessException("该分类下有菜品，删除失败！");
        }


        LambdaQueryWrapper<Setmeal> slqw = Wrappers.lambdaQuery(Setmeal.class)
                .eq(Setmeal::getCategoryId, id);


        // 如果查询到的套餐，表示在使用，要抛出业务异常
        int setmealCount = setmealService.count(slqw);
        if (setmealCount > 0) {
            throw new BusinessException("该分类下有套餐，删除失败！");
        }

        // 否则，允许删除
        boolean result = this.removeById(id);

        // 组织数据并返回
        if (result) {
            return R.success("删除分类成功", null);
        }
        return R.fail("删除分类失败");
    }

    /**
     * 修改，并检查名称是否重复
     *
     * @param category 要修改的参数
     * @return 修改是否成功
     */
    @Override
    public R updateByIdWithNameCheck(Category category) {
        // TODO 参数校验

        checkNameDuplacate(category);
        // 不重复，保存修改
        // 组织数据并返回
        if (updateById(category)) {
            return R.success("修改成功", null);
        }
        return R.fail("修改失败");
    }

    /**
     * 根据条件查询分类，目前的条件只有type
     *
     * @param category 查询条件封装的实体对象
     * @return 符合要求的所有分类对象
     */
    @Override
    public R<List<Category>> listByCondition(Category category) {
        // TODO 参数校验

        // 构建查询条件对象和排序规则
        LambdaQueryWrapper<Category> qw = Wrappers.<Category>lambdaQuery()
                .eq(category.getType() != null, Category::getType, category.getType())
                .like(StringUtils.isNotBlank(category.getName()), Category::getName, category.getName())
                .orderByAsc(Category::getSort)
                .orderByDesc(Category::getUpdateTime);


        // 查询 封装数据并返回
        List<Category> categories = this.list(qw);

        if (ObjectUtils.isEmpty(categories)) {
            return R.fail("查询失败！");
        }
        return R.success("查询成功",categories);
    }


    /**
     * 检查名称是否重复，如果重复则抛出异常
     *
     * @param category 包含名称的实体对象
     */
    private void checkNameDuplacate(Category category) {
        // 判断名称是否重复
        String name = category.getName();
        LambdaQueryWrapper<Category> qw = Wrappers.lambdaQuery(Category.class)
                .eq(StringUtils.isNotBlank(name), Category::getName, name)
                .ne(category.getId() != null, Category::getId, category.getId());
        if (this.count(qw) > 0) {
            // 重复，则抛出异常
            throw new BusinessException("分类名[" + name + "]重复，请修改后再试！");
        }
    }
}
